package com.service.screenWeb.task;

import com.alibaba.fastjson.JSONArray;
import com.service.config.utils.ModelMapperUtil;
import com.service.config.utils.RedisUtil;

import com.service.screenWeb.dao.ProgrammeInfoDao;
import com.service.screenWeb.dao.ScreenUserDao;
import com.service.screenWeb.dto.*;
import com.service.screenWeb.entity.ProgrammeInfo;
import com.service.screenWeb.entity.ScreenUser;
import com.service.screenWeb.enums.AssemblyEnum;
import com.service.screenWeb.service.UserServiceInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.service.config.utils.DateUtil.*;

/**
 * @program: CloudCampusService
 * @description: 定时任务
 * @author: rui
 * @create: 2021-03-30 15:35
 **/
@Service
@Async
@Slf4j
public class ScheduleService {

    @Resource
    RedisUtil redisUtil;
    @Resource
    UserServiceInfoService userServiceInfoService;
    @Resource
    CloudCampusApi cloudCampusApi;

    @Resource
    ScreenUserDao screenUserDao;


    @Resource
    ProgrammeInfoDao programmeInfoDao;
    public void getLoginUserDispose() {

        //查找在线用户Api账号列表
        List<ScreenUser> userInfos = new ArrayList<>();
        List<ScreenUser> screenUsers = screenUserDao.queryAll(new ScreenUser());
        screenUsers.forEach(userInfo -> {
            Set<String> strings = redisUtil.redisLike(userInfo.getUserId());
            if (strings.size()>0 ) {
                userInfos.add(userInfo);
            }
        });

        //筛选出来用户api账号状态正常的获取数据
        List<ScreenUser> list = new ArrayList<>();
        userInfos.forEach(user -> {
            if (user.isStatus()) {
                if (user.getDomain() == null || "".equals(user.getDomain())) {
                    user.setDomain("naas");
                }
                list.add(user);
            }
        });

        if (list.size() > 0) {
            //根据用户id分组
            Map<String, List<ScreenUser>> map = new HashMap<>();
            list.stream().collect(Collectors.groupingBy(ScreenUser::getUserId))
                    .forEach(map::put);
            map.entrySet().forEach(userList -> {
                String assemblyInfo = "";
                ProgrammeInfo programmeInfo = new ProgrammeInfo();
                programmeInfo.setUserId(userList.getKey());
                List<ProgrammeInfo> programmeInfos = programmeInfoDao.queryAll(programmeInfo);
                for (ProgrammeInfo programmeInfo1 : programmeInfos) {
                    if (programmeInfo1.getStatus()) {
                        getAssembly(programmeInfo1.getLayoutInfo(),userList.getValue());
                    }
                }

            });

        } else {
            log.info("The Online User list is null!");
        }
    }

    /**
     * 关联账号成功后就查询一次
     * @param screenUser
     */
    public void getLoginUserDispose(ScreenUser screenUser) {
        List<ScreenUser> screenUsers = new ArrayList<>();
        screenUsers.add(screenUser);
            //筛选出来用户api账号状态正常的获取数据
        if (screenUsers.size() > 0) {
            //根据用户id分组
            Map<String, List<ScreenUser>> map = new HashMap<>();
            screenUsers.stream().collect(Collectors.groupingBy(ScreenUser::getUserId))
                    .forEach(map::put);
            map.entrySet().forEach(userList -> {
                String assemblyInfo = "";
                ProgrammeInfo programmeInfo = new ProgrammeInfo();
                programmeInfo.setUserId(userList.getKey());
                List<ProgrammeInfo> programmeInfos = programmeInfoDao.queryAll(programmeInfo);
                for (ProgrammeInfo programmeInfo1 : programmeInfos) {
                    if (programmeInfo1.getStatus()) {
                        getAssembly(programmeInfo1.getLayoutInfo(),userList.getValue());
                    }
                }
            });

        } else {
            log.info("The Online User list is null!");
        }
    }
    /**
     * 获取组件
     *
     * @param screenUsers
     */
    private void getAssembly(String assemblyInfo ,List<ScreenUser> screenUsers) {
        //根据模板获取组件
        List<ApiAccountDto> apiAccountDtos = new ArrayList<>();
        screenUsers.forEach(screenUser -> {
            ApiAccountDto apiAccountDto = new ApiAccountDto();
            screenUser.setAssemblyInfo(assemblyInfo);
            HttpHeaders requestHeaders = getToken(screenUser);
            //获取站点
            List<SiteDto> sites = cloudCampusApi.getSites(requestHeaders, screenUser.getDomain());
            apiAccountDto.setRequestHeaders(requestHeaders);
            apiAccountDto.setSites(sites);
            apiAccountDto.setScreenUser(screenUser);
            apiAccountDtos.add(apiAccountDto);
        });

        apiAccountDtos.forEach(apiAccountDto -> {
            //获取站点
            List<ProgrammeInfoViewDto> assemblies = JSONArray.parseArray(apiAccountDto.getScreenUser().getAssemblyInfo(), ProgrammeInfoViewDto.class);

            //组件1,3,6,9 组件都是关于站点和设备的，所以走一次方法（1-设备总数柱状图，3-分类型设备数量,6-站点的地图分布,9-设备状态总览）
            //组件7,8 是关于终端用户的（7-终端用户在线时长，8-有限无线接入人数）

            List<String> list = new ArrayList<>();
            assemblies.forEach(assembly1 -> {
                if (3 == assembly1.getNumber() || 6==assembly1.getNumber() || 9==assembly1.getNumber()) {
                    list.add(String.valueOf(1));
                } else if (8 ==assembly1.getNumber() || 4 ==assembly1.getNumber() || 17 ==assembly1.getNumber()) {
                    list.add("7");
                    //流量（日、月、年）
                } else if(15 ==assembly1.getNumber() || 16 ==assembly1.getNumber()){
                    list.add("5");
                    //健康度
                }else if(19 ==assembly1.getNumber() || 20 ==assembly1.getNumber() || 21 ==assembly1.getNumber()){
                    list.add("18");
                }else {
                    list.add(String.valueOf(assembly1.getNumber()));
                }
            });

            //去重
            List<String> list1 = list.stream().distinct().collect(Collectors.toList());
            try {
                if (list1.size() > 0) {
                    list1.forEach(assem -> {
                        AssemblyEnum assemblyEnum = AssemblyEnum.get(assem);
                        switch (assemblyEnum) {
                            //站点的地图分布（默认大屏）
                            case SITE_DEVICE:
                                getSiteDevices(apiAccountDtos);
                                break;
                            //在线人数
//                            case ONLINE:
//                                getRealTimeAccess(apiAccountDtos);
//                                break;
                                //流量
                            case TRAFFIC:
                                getTraffic(apiAccountDtos);
                                break;
                            //应用流量
                            case APP_TRAFFIC:
                                getSsidTraffic(apiAccountDtos);
                                break;
                            //终端用户在线时长列表
                            case TERMINAL_USER:
                                getTerminalUserList1(apiAccountDtos);
                                break;
                            case SITE_HEALTH:
                                getSiteHealth(apiAccountDtos);
                            default:
                                break;
                        }
                    });
                }
            } catch (Exception e) {
                log.error("the shechedule run error::"+ e.getMessage());

            }

        });

    }
    /**
     * 站点健康度查询
     * @param apiAccountDtos
     */
    private void  getSiteHealth(List<ApiAccountDto> apiAccountDtos){
        List<SiteHealthDto> siteList = new ArrayList<>();
        List<DeviceHealthDto> deviceList = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            siteList.addAll(cloudCampusApi.getSiteHealth(sites, requestHeaders, domain));
            deviceList.addAll(cloudCampusApi.getDeviceHealth(sites, requestHeaders, domain));

        });
        siteList.forEach(siteHealthDto -> {
            deviceList.forEach(deviceHealthDto -> {
                if(siteHealthDto.getSiteId().equals(deviceHealthDto.getSiteId())){
                    siteHealthDto.setDeviceHealthPoint(deviceHealthDto.getDeviceHealthPoint());
                    siteHealthDto.setTimestamp(deviceHealthDto.getTimestamp());
                }
            });
        });
        if(siteList.size()>0){
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_SITE_HEALTH"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_SITE_HEALTH"), siteList);
        }
    }
    private void getTerminalUserList1(List<ApiAccountDto> apiAccountDtos) {
        getTerminalUserList(apiAccountDtos);
        getTerminalUserListOff(apiAccountDtos);
    }

    /**
     * 查询TOP N SSID流量和最近在线用户数
     * @param apiAccountDtos
     */
    private void getSsidTraffic(List<ApiAccountDto> apiAccountDtos) {
        List<SiteDto> allAites = new ArrayList<>();
        List<TopNSsidTrafficDto> list = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            List<TopNSsidTrafficDto> list1= cloudCampusApi.getSsidTrafficDetail(sites, requestHeaders, domain);
            list.addAll(list1);
            allAites.addAll(sites);
        });
        if(list.size()>0){
            redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_TOPN_SSID_TRAFFIC"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_TOPN_SSID_TRAFFIC"), list);
        }

    }

    /**
     * 获取用户token
     *
     * @param screenUser
     * @return
     */
    public HttpHeaders getToken(ScreenUser screenUser) {

        HttpHeaders requestHeaders = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        requestHeaders.setContentType(type);
        requestHeaders.add("Accept", MediaType.APPLICATION_JSON.toString());

        String userName = screenUser.getTenantName();
        String password = screenUser.getTenantPwd();
        String token = "";

        try {
            if (redisUtil.exist(userName.concat("token"))) {
                token = redisUtil.getValue(userName.concat("token"));
            } else {
                //获取token
                token = cloudCampusApi.getToken(userName, password, requestHeaders, screenUser.getDomain());
                redisUtil.set(userName.concat("token"), 1, token, 10);

            }
            //获取站点
            requestHeaders.add("X-AUTH-TOKEN", token);
        } catch (Exception e) {
            log.error("token Access failure!");
        }

        return requestHeaders;
    }


    /**
     * 获取站点设备数据
     *
     * @param
     */
    public void getSiteDevices(List<ApiAccountDto> apiAccountDtos) {
        List<DeviceDto> deviceDtos = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            List<DeviceDto> list = cloudCampusApi.getDevices(sites, requestHeaders, domain);
            if (list != null) {
                deviceDtos.addAll(list);
            }
            allAites.addAll(sites);
        });


        if (deviceDtos != null) {
            //根据站点id 给设备分组
            Map<String, List<DeviceDto>> map = new HashMap<>();
            deviceDtos.stream().collect(Collectors.groupingBy(DeviceDto::getSiteId))
                    .forEach(map::put);

            allAites.forEach(siteDto -> {
                map.entrySet().stream().forEach(siteEntry -> {
                    if (siteDto.getId().equals(siteEntry.getKey())) {
                        siteDto.setDeviceCounts(siteEntry.getValue().size());
                        siteDto.setDevice(siteEntry.getValue());
                    }
                });
            });
        }
        if (allAites != null) {
            //redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_siteData"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_siteData"), allAites);
        }

    }


    /**
     * 获取实时接入用户数
     *
     * @param
     * @param
     */
    private void getRealTimeAccess(List<ApiAccountDto> apiAccountDtos) {
        //获取设备在线人数
//        List<PortalUserDto> portalUserDtos = cloudCampusApi.getProtalUsers(sites, requestHeaders);
        List<RealTimeDto> list = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            try {
                List<RealTimeDto> list1 = cloudCampusApi.getDetailMinuDetil(sites, requestHeaders, domain);
                if (list1 != null) {
                    list.addAll(list1);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            allAites.addAll(sites);
        });
        if (list != null || list.size() > 0) {
            //redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_realUser"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_realUser"), list);
        }

    }


    /**
     * 获取网络流量
     *
     * @param
     * @param
     * @param
     */
    private void getTraffic(List<ApiAccountDto> apiAccountDtos) {
        String requestParmDay = "?timeDimension=day&top=0&beginTime=" +date2TimeStamp(datetoString(initDateByDay()),"yyyy-MM-dd HH:mm:ss") + "&endTime=" + timeStamp();
        String requestParmMonth = "?timeDimension=month&top=0&beginTime=" +date2TimeStamp(datetoString(initDateByMonth()),"yyyy-MM-dd HH:mm:ss") + "&endTime=" + timeStamp();
        String requestParmYear = "?timeDimension=year&top=0&beginTime=" +date2TimeStamp(datetoString(initDateByYear()),"yyyy-MM-dd HH:mm:ss") + "&endTime=" + timeStamp();
//        String requestParmHistory = "?timeDimension=year&top=0&beginTime=" +date2TimeStamp(datetoString(initDateByHistory()),"yyyy-MM-dd HH:mm:ss") + "&endTime=" + timeStamp();
        String[] requestParms = {requestParmDay, requestParmMonth, requestParmYear};
        String[] keys = {"_traffic", "_trafficMonth", "_trafficYear"};
        for(int i = 0; i < requestParms.length; i++){
            List<RealTimeDto> realTimeDtos = getTrafficByDimension(apiAccountDtos, requestParms[i]);
            if (realTimeDtos.size() > 0) {
                //redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat(keys[i]));
                redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat(keys[i]), realTimeDtos);
            }
        }
    }

    /**
     * 获取当日，月，年
     *
     */
    private List<RealTimeDto> getTrafficByDimension(List<ApiAccountDto> apiAccountDtos, String requestParm){
        List<DeviceTrafficDto> deviceTrafficDtos = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            List<DeviceTrafficDto> list = cloudCampusApi.getDeviceTrafficDetail(sites, requestHeaders, domain, requestParm);
            if (list != null) {
                deviceTrafficDtos.addAll(list);
            }
            allAites.addAll(sites);
        });

        List<RealTimeDto> realTimeDtos = new ArrayList<>();
        allAites.forEach(siteDto -> {
            RealTimeDto realTimeDto = new RealTimeDto();
            realTimeDto.setSiteId(siteDto.getId());
            realTimeDto.setName(siteDto.getName());
            realTimeDto.setValue(0);
            realTimeDtos.add(realTimeDto);
        });

        if (deviceTrafficDtos != null) {
            Map<String, List<DeviceTrafficDto>> map = new HashMap<>();
            deviceTrafficDtos.stream().collect(Collectors.groupingBy(DeviceTrafficDto::getSiteId)).forEach(map::put);
            List<RealTimeDto> list = new ArrayList();
            map.entrySet().forEach(deviceList -> {
                Double siteTraffic = 0d;
                RealTimeDto realTimeDto = new RealTimeDto();
                siteTraffic = deviceList.getValue().stream().collect(Collectors.summingDouble(DeviceTrafficDto::getUpTraffic));
                realTimeDto.setSiteId(deviceList.getKey());
                try {
                    realTimeDto.setValue((int) Math.ceil(siteTraffic));
                }catch (Exception e) {
                    log.error(e.getMessage());
                }
                list.add(realTimeDto);
            });

            if (list.size() > 0) {
                realTimeDtos.forEach(realTimeDto -> {
                    list.forEach(sitesTraffic -> {
                        if ((sitesTraffic.getValue() != null) && realTimeDto.getSiteId().equals(sitesTraffic.getSiteId())) {
                            realTimeDto.setValue(sitesTraffic.getValue());
                        }
                    });
                });
            }
        }
        return realTimeDtos;
    }

    /**
     * 获取TopN应用流量
     *
     * @param
     * @param
     * @param
     */
    private void getAppTraffic(List<ApiAccountDto> apiAccountDtos) {
        List<AppInfoDto> list = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            List<AppInfoDto> list1 = cloudCampusApi.getAPPTrafficDetail(sites, requestHeaders, domain);
            if (list1 != null) {
                list.addAll(list1);
            }
            allAites.addAll(sites);
        });

        if (list.size() > 0) {
            //redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_app_traffic"));
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_app_traffic"), list);
        }
    }


    /**
     * 获取在线时长用户列表
     *
     * @param
     * @param
     * @param
     */
    private void getTerminalUserList(List<ApiAccountDto> apiAccountDtos) {

        List<TerminalUserDto> list = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        List<RealTimeDto> realTimeDtoList = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            Map online = cloudCampusApi.getTerminalUserList("online", sites, requestHeaders, domain);
            if (online != null) {
                List<RealTimeDto> realTimeDtos = ModelMapperUtil.strictMapList(online.get("realTimeDtos"), RealTimeDto.class);
                List<TerminalUserDto> terminalUserDto = ModelMapperUtil.strictMapList(online.get("TerminalUserDto"), TerminalUserDto.class);
                realTimeDtoList.addAll(realTimeDtos);
                list.addAll(terminalUserDto);
            }
            allAites.addAll(sites);
        });

        if (list.size() > 0) {
            //redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_realUser"));
            //redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_online_terminal_user"));
            //存数据
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_online_terminal_user"), list);
            //存数据
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_realUser"), realTimeDtoList);
        }
    }
    /**
     * 获取不在线时长用户列表
     *
     * @param
     * @param
     * @param
     */
    private void getTerminalUserListOff(List<ApiAccountDto> apiAccountDtos) {

        List<TerminalUserDto> list = new ArrayList<>();
        List<SiteDto> allAites = new ArrayList<>();
        List<RealTimeDto> realTimeDtoList = new ArrayList<>();
        apiAccountDtos.forEach(apiAccountDto -> {
            List<SiteDto> sites = apiAccountDto.getSites();
            HttpHeaders requestHeaders = apiAccountDto.getRequestHeaders();
            String domain = apiAccountDto.getScreenUser().getDomain();
            //offline---离线
            Map offline = cloudCampusApi.getTerminalUserList("offline", sites, requestHeaders, domain);
            if (offline != null) {
                List<RealTimeDto> realTimeDtos = ModelMapperUtil.strictMapList(offline.get("realTimeDtos"), RealTimeDto.class);
                List<TerminalUserDto> terminalUserDto = ModelMapperUtil.strictMapList(offline.get("TerminalUserDto"), TerminalUserDto.class);
                realTimeDtoList.addAll(realTimeDtos);
                list.addAll(terminalUserDto);
            }
            allAites.addAll(sites);
        });

        if (list.size() > 0) {
            //redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_offline_realUser"));
            //redisUtil.delete(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_offline_terminal_user"));
            //存数据
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_offline_terminal_user"), list);
            redisUtil.setList(apiAccountDtos.get(0).getScreenUser().getUserId().concat("_offline_realUser"),realTimeDtoList);
        }
    }


    /**
     * byte(字节)根据长度转成kb(千字节)和mb(兆字节)     *     * @param bytes     * @return
     */
    public static void bytesToMb(Double bytes) {
        BigDecimal filesize = new BigDecimal(bytes);
        BigDecimal megabyte = new BigDecimal(1024 * 1024);
        float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP).floatValue();
    }
}
